<template>
  <div class="chat-input-area">
    <div
      :class="['edit-chat-container', isEmpty ? '' : 'not-empty']"
      contenteditable="true"
      @paste.prevent="onPaste"
      @keydown="onKeydown"
      @compositionstart="compositionFlag = true"
      @compositionend="onCompositionEnd"
      @input="onEditorInput"
      @mousedown="onMousedown"
      ref="content"
      @blur="onBlur"
    ></div>
    <chat-at-box
      @select="onAtSelect"
      :search-text="atSearchText"
      ref="atBox"
      :ownerId="ownerId"
      :members="groupMembers"
    ></chat-at-box>
  </div>
</template>

<script>
import ChatAtBox from "./ChatAtBox";
export default {
  name: "ChatInput",
  components: { ChatAtBox },
  props: {
    ownerId: {
      type: Number,
    },
    groupMembers: {
      type: Array,
    },
  },
  data() {
    return {
      imageList: [],
      fileList: [],
      currentId: 0,
      atSearchText: null,
      compositionFlag: false,
      atIng: false,
      isEmpty: true,
      changeStored: true,
      blurRange: null,
    };
  },
  methods: {
    onPaste(e) {
      this.isEmpty = false;
      let txt = e.clipboardData.getData("Text");
      if (
        !window.getSelection().getRangeAt ||
        !window.getSelection().getRangeAt(0)
      )
        return;
      let range = window.getSelection().getRangeAt(0);
      if (
        range.startContainer !== range.endContainer ||
        range.startOffset !== range.endOffset
      ) {
        range.deleteContents();
      }
      console.log(e.clipboardData.files);
      let clipboardDatItems = e.clipboardData.items; // 获取剪贴板内容
      console.log("🚀🚀🚀 ~ onPaste ~ clipboardDatItems:", clipboardDatItems);
      let index = 0;
      for (let item of clipboardDatItems) {
        if (item.type.indexOf("image") !== -1) {
          // 只处理图片类型的数据
          let file = item.getAsFile();
          if (!file) return;

          let imagePush = {
            fileId: this.generateId(),
            file: file,
            url: URL.createObjectURL(file),
          };

          // if (imagePush.file.path) return
          if (index > 0) return;
          index++;

          this.imageList[imagePush.fileId] = imagePush;
          let line = this.newLine();
          let imageElement = document.createElement("img");
          imageElement.className = "chat-image no-text";
          imageElement.src = imagePush.url;
          imageElement.dataset.imgId = imagePush.fileId;
          line.appendChild(imageElement);
          let after = document.createTextNode("\u00A0");
          line.appendChild(after);
          this.selectElement(after, 1);
        } else {
          let asFile = item.getAsFile();
          console.log("🚀🚀🚀 ~ onPaste ~ asFile:", item.getAsFile());
          if (!asFile) {
            continue;
          }
          let filePush = { fileId: this.generateId(), file: asFile };
          this.fileList[filePush.fileId] = filePush;
          let line = this.newLine();
          let fileElement = this.createFile(filePush);
          line.appendChild(fileElement);
          let after = document.createTextNode("\u00A0");
          line.appendChild(after);
          this.selectElement(after, 1);
        }
      }

      // 粘贴图片和文件时，这里没有数据
      if (txt && typeof txt == "string") {
        let textNode = document.createTextNode(txt);
        range.insertNode(textNode);
        range.collapse();
        return;
      }

      // let items = (e.clipboardData || window.clipboardData).items
      // console.log(items)
      // if (items.length) {

      // 	for (let i = 0; i < items.length; i++) {
      // 		if (items[i].type.indexOf('image') !== -1) {
      // 			let file = items[i].getAsFile();
      // 			let imagePush = {
      // 				fileId: this.generateId(),
      // 				file: file,
      // 				url: URL.createObjectURL(file)
      // 			};
      // 			console.log(file)
      // 			if (imagePush.file.path) return
      // 			this.imageList[imagePush.fileId] = (imagePush);
      // 			let line = this.newLine();
      // 			let imageElement = document.createElement('img');
      // 			imageElement.className = 'chat-image no-text';
      // 			imageElement.src = imagePush.url;
      // 			imageElement.dataset.imgId = imagePush.fileId;
      // 			line.appendChild(imageElement);
      // 			let after = document.createTextNode('\u00A0');
      // 			line.appendChild(after);
      // 			this.selectElement(after, 1);
      // 		} else {
      // 			let asFile = items[i].getAsFile();
      // 			if (!asFile) {
      // 				continue;
      // 			}
      // 			let filePush = { fileId: this.generateId(), file: asFile };
      // 			this.fileList[filePush.fileId] = (filePush)
      // 			let line = this.newLine();
      // 			let fileElement = this.createFile(filePush);
      // 			line.appendChild(fileElement);
      // 			let after = document.createTextNode('\u00A0');
      // 			line.appendChild(after);
      // 			this.selectElement(after, 1);
      // 		}
      // 	}
      // }
      range.collapse();
    },
    selectElement(element, endOffset) {
      let selection = window.getSelection();
      // 插入元素可能不是立即执行的，vue可能会在插入元素后再更新dom
      this.$nextTick(() => {
        let t1 = document.createRange();
        t1.setStart(element, 0);
        t1.setEnd(element, endOffset || 0);
        if (element.firstChild) {
          t1.selectNodeContents(element.firstChild);
        }
        t1.collapse();
        selection.removeAllRanges();
        selection.addRange(t1);
        // 需要时自动聚焦
        if (element.focus) {
          element.focus();
        }
      });
    },
    onCompositionEnd(e) {
      this.compositionFlag = false;
      this.onEditorInput(e);
    },
    onKeydown(e) {
      if (e.keyCode === 13) {
        e.preventDefault();
        e.stopPropagation();
        if (this.atIng) {
          console.log("选中at的人");
          this.$refs.atBox.select();
          return;
        }
        if (e.ctrlKey) {
          let line = this.newLine();
          let after = document.createTextNode("\u00A0");
          line.appendChild(after);
          this.selectElement(line.childNodes[0], 0);
        } else {
          // 中文输入标记
          if (this.compositionFlag) {
            return;
          }
          this.submit();
        }
        return;
      }
      // 删除键
      if (e.keyCode === 8) {
        console.log("delete");
        // 等待dom更新
        setTimeout(() => {
          let s = this.$refs.content.innerHTML.trim();
          // 空dom时，需要刷新dom
          console.log(s);
          if (s === "" || s === "<br>" || s === "<div>&nbsp;</div>") {
            // 拼接随机长度的空格，以刷新dom
            this.empty();
            this.isEmpty = true;
            this.selectElement(this.$refs.content);
          } else {
            this.isEmpty = false;
          }
        });
      }
      // at框打开时，上下键移动特殊处理
      if (this.atIng) {
        if (e.keyCode === 38) {
          e.preventDefault();
          e.stopPropagation();
          this.$refs.atBox.moveUp();
        }
        if (e.keyCode === 40) {
          e.preventDefault();
          e.stopPropagation();
          this.$refs.atBox.moveDown();
        }
      }
    },
    onAtSelect(member) {
      this.atIng = false;
      // 选中输入的 @xx 符
      let blurRange = this.blurRange;
      let endContainer = blurRange.endContainer;
      let startOffset = endContainer.data.indexOf("@" + this.atSearchText);
      let endOffset = startOffset + this.atSearchText.length + 1;
      blurRange.setStart(blurRange.endContainer, startOffset);
      blurRange.setEnd(blurRange.endContainer, endOffset);
      blurRange.deleteContents();
      blurRange.collapse();
      console.log("onAtSelect");
      this.focus();
      // 创建元素节点
      let element = document.createElement("SPAN");
      element.className = "chat-at-user";
      element.dataset.id = member.userId;
      element.contentEditable = "false";
      element.innerText = `@${member.showNickName}`;
      blurRange.insertNode(element);
      // 光标移动到末尾
      blurRange.collapse();

      // 插入空格
      let textNode = document.createTextNode("\u00A0");
      blurRange.insertNode(textNode);

      blurRange.collapse();
      this.atSearchText = "";
      this.selectElement(textNode, 1);
    },
    onEditorInput(e) {
      this.isEmpty = false;
      this.changeStored = false;
      if (this.$props.groupMembers && !this.compositionFlag) {
        let selection = window.getSelection();
        if (!selection.getRangeAt(0) || !selection.getRangeAt(0)) return;
        let range = selection.getRangeAt(0);
        // 截取@后面的名称作为过滤条件，并以空格结束
        let endContainer = range.endContainer;
        let endOffset = range.endOffset;
        let textContent = endContainer.textContent;
        let startIndex = -1;
        for (let i = endOffset; i >= 0; i--) {
          if (textContent[i] === "@") {
            startIndex = i;
            break;
          }
        }
        // 没有at符号，则关闭弹窗
        if (startIndex === -1) {
          this.$refs.atBox.close();
          return;
        }

        let endIndex = endOffset;
        for (let i = endOffset; i < textContent.length; i++) {
          if (textContent[i] === " ") {
            endIndex = i;
            break;
          }
        }
        this.atSearchText = textContent
          .substring(startIndex + 1, endIndex)
          .trim();
        // 打开选择弹窗
        if (this.atSearchText == "") {
          this.showAtBox(e);
        }
      }
    },
    onBlur(e) {
      this.updateRange();
    },
    onMousedown() {
      if (this.atIng) {
        this.$refs.atBox.close();
        this.atIng = false;
      }
    },
    insertEmoji(emojiText) {
      let emojiElement = document.createElement("img");
      emojiElement.className = "chat-emoji no-text";
      emojiElement.dataset.emojiCode = emojiText;
      emojiElement.src = this.$emo.textToUrl(emojiText);

      let blurRange = this.blurRange;
      if (!blurRange) {
        this.focus();
        this.updateRange();
        blurRange = this.blurRange;
      }
      if (
        blurRange.startContainer !== blurRange.endContainer ||
        blurRange.startOffset !== blurRange.endOffset
      ) {
        blurRange.deleteContents();
      }
      blurRange.insertNode(emojiElement);
      blurRange.collapse();

      let textNode = document.createTextNode("\u00A0");
      blurRange.insertNode(textNode);
      blurRange.collapse();

      this.selectElement(textNode);
      this.updateRange();
      this.isEmpty = false;
    },
    generateId() {
      return this.currentId++;
    },
    createFile(filePush) {
      let file = filePush.file;
      let fileId = filePush.fileId;
      let container = document.createElement("div");
      container.className = "chat-file-container no-text";
      container.contentEditable = "false";
      container.dataset.fileId = fileId;

      let left = document.createElement("div");
      left.className = "file-position-left";
      container.appendChild(left);

      let icon = document.createElement("div");
      icon.className = "el-icon-document";
      left.appendChild(icon);

      let right = document.createElement("div");
      right.className = "file-position-right";
      container.appendChild(right);

      let fileName = document.createElement("div");
      fileName.className = "file-name";
      fileName.innerText = file.name;

      let fileSize = document.createElement("div");
      fileSize.className = "file-size";
      fileSize.innerText = this.sizeConvert(file.size);

      right.appendChild(fileName);
      right.appendChild(fileSize);

      return container;
    },
    sizeConvert(len) {
      if (len < 1024) {
        return len + "B";
      } else if (len < 1024 * 1024) {
        return (len / 1024).toFixed(2) + "KB";
      } else if (len < 1024 * 1024 * 1024) {
        return (len / 1024 / 1024).toFixed(2) + "MB";
      } else {
        return (len / 1024 / 1024 / 1024).toFixed(2) + "GB";
      }
    },
    updateRange() {
      let selection = window.getSelection();
      if (!selection.getRangeAt || !selection.getRangeAt(0)) return;
      this.blurRange = selection.getRangeAt(0);
    },
    newLine() {
      let selection = window.getSelection();
      if (!selection.getRangeAt || !selection.getRangeAt(0)) return;
      let range = selection.getRangeAt(0);
      let divElement = document.createElement("div");
      let endContainer = range.endContainer;
      let parentElement = endContainer.parentElement;
      if (parentElement.parentElement === this.$refs.content) {
        divElement.innerHTML = endContainer.textContent
          .substring(range.endOffset)
          .trim();
        endContainer.textContent = endContainer.textContent.substring(
          0,
          range.endOffset
        );
        // 插入到当前div（当前行）后面
        parentElement.insertAdjacentElement("afterend", divElement);
      } else {
        divElement.innerHTML = "";
        this.$refs.content.append(divElement);
      }
      return divElement;
    },
    clear() {
      this.empty();
      this.imageList = [];
      this.fileList = [];
    },
    empty() {
      this.$refs.content.innerHTML = "";
      let line = this.newLine();
      let after = document.createTextNode("\u00A0");
      line.appendChild(after);
      this.$nextTick(() => this.selectElement(after));
    },
    showAtBox(e) {
      this.atIng = true;
      // show之后会自动更新当前搜索的text
      // this.atSearchText = "";
      let selection = window.getSelection();
      if (!selection.getRangeAt || !selection.getRangeAt(0)) return;
      let range = selection.getRangeAt(0);
      // 光标所在坐标
      let pos = range.getBoundingClientRect();
      this.$refs.atBox.open({
        x: pos.x,
        y: pos.y,
      });
      // 记录光标所在位置
      this.updateRange();
    },
    html2Escape(strHtml) {
      return strHtml.replace(/[<>&"]/g, function (c) {
        return {
          "<": "&lt;",
          ">": "&gt;",
          "&": "&amp;",
          '"': "&quot;",
        }[c];
      });
    },
    submit() {
      let nodes = this.$refs.content.childNodes;
      let fullList = [];
      let tempText = "";
      let atUserIds = [];
      let each = (nodes) => {
        for (let i = 0; i < nodes.length; i++) {
          let node = nodes[i];
          if (!node) {
            continue;
          }
          if (node.nodeType === 3) {
            tempText += this.html2Escape(node.textContent);
            continue;
          }
          let nodeName = node.nodeName.toLowerCase();
          if (nodeName === "script") {
            continue;
          }
          let text = tempText.trim();
          if (nodeName === "img") {
            let imgId = node.dataset.imgId;
            if (imgId) {
              if (text) {
                fullList.push({
                  type: "text",
                  content: text,
                  atUserIds: atUserIds,
                });
                tempText = "";
                atUserIds = [];
              }
              fullList.push({
                type: "image",
                content: this.imageList[imgId],
              });
            } else {
              let emojiCode = node.dataset.emojiCode;
              tempText += emojiCode;
            }
          } else if (nodeName === "div") {
            let fileId = node.dataset.fileId;
            // 文件
            if (fileId) {
              if (text) {
                fullList.push({
                  type: "text",
                  content: text,
                  atUserIds: atUserIds,
                });
                tempText = "";
                atUserIds = [];
              }
              fullList.push({
                type: "file",
                content: this.fileList[fileId],
              });
            } else {
              tempText += "\n";
              each(node.childNodes);
            }
          } else if (nodeName === "span") {
            if (node.dataset.id) {
              tempText += node.innerHTML;
              atUserIds.push(node.dataset.id);
            } else {
              tempText += node.outerHtml;
            }
          }
        }
      };
      each(nodes);
      let text = tempText.trim();
      if (text !== "") {
        fullList.push({
          type: "text",
          content: text,
          atUserIds: atUserIds,
        });
      }
      this.$emit("submit", fullList);
    },
    focus() {
      this.$refs.content.focus();
    },
  },
};
</script>

<style lang="scss">
.chat-input-area {
  width: 100%;
  height: 100%;
  position: relative;

  .edit-chat-container {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    outline: none;
    padding: 5px;
    line-height: 1.5;
    font-size: var(--im-font-size);
    text-align: left;
    overflow-y: auto;

    // 单独一行时，无法在前面输入的bug
    > div:before {
      content: "\00a0";
      font-size: 14px;
      position: absolute;
      top: 0;
      left: 0;
    }

    .chat-image {
      display: block;
      max-width: 200px;
      max-height: 100px;
      border: 1px solid #e6e6e6;
      cursor: pointer;
    }

    .chat-emoji {
      width: 30px;
      height: 30px;
      vertical-align: top;
      cursor: pointer;
    }

    .chat-file-container {
      max-width: 65%;
      padding: 10px;
      border: 2px solid #587ff0;
      display: flex;
      background: #eeec;
      border-radius: 10px;

      .file-position-left {
        display: flex;
        width: 80px;
        justify-content: center;
        align-items: center;

        .el-icon-document {
          font-size: 40px;
          text-align: center;
          color: #d42e07;
        }
      }

      .file-position-right {
        flex: 1;

        .file-name {
          font-size: 16px;
          font-weight: 600;
          color: #66b1ff;
        }

        .file-size {
          font-size: 14px;
          font-weight: 600;
        }
      }
    }

    .chat-at-user {
      color: #00f;
      border-radius: 3px;
    }
  }

  .edit-chat-container > div:nth-of-type(1):after {
    content: "请输入消息（按Ctrl+Enter键换行）";
    color: gray;
  }

  .edit-chat-container.not-empty > div:nth-of-type(1):after {
    content: none;
  }
}
</style>
